package com.sali.handler;

import cn.hutool.core.io.FileUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import com.sali.constants.CommonContent;
import com.sali.enums.ProtocolHandleTypeEnum;
import com.sali.model.*;
import com.sali.rule.Rule;
import lombok.Builder;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.util.StringUtils;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @description: 解析模型文件为内存模型
 * @author: sali
 * @date: 2024/7/16 21:18.
 * @version: 1.0
 */
@Slf4j
@Builder(builderMethodName = "createBuilder")
public class ProtocolModelLoad {
    /**
     * 文件扩展名
     */
    private static final String FILE_EXTENSION = "xlsx";

    /**
     * 协议容器默认容量
     */
    private static final int PROTOCOL_INITIAL_CAPACITY = 30;

    /**
     * 使用索引下标处理的协议类型
     */
    private static final String[] INDEX_HANDLE_PROTOCOL = {"call", "voip", "voipfax"};

    /**
     * 转换字段key
     */
    private static final String DST_FIELD_NAME_KEY = "dstFieldName";
    /**
     * 原始字段key
     */
    private static final String SRC_FIELD_NAME_KEY = "srcFieldName";
    /**
     * call和voip协议解析序号key
     */
    private static final String SRC_NUMBER_KEY = "srcNumber";
    /**
     * 字段类型key
     */
    private static final String FIELD_TYPE_KEY = "fieldType";

    /**
     * 是否必须字段
     */
    private static final String REQUIRED_FIELD_KEY = "isRequiredField";

    /**
     * 解析规则
     */
    private static final String HANDLE_RULE_KEY = "handleRule";

    /**
     * 默认值key
     */
    private static final String DEFAULT_VALUE_KEY = "defaultValue";

    /**
     * 空字符
     */
    private static final String EMPTY_VALUE_KEY = "\"\"";


    /**
     * 加载文件解析表格内容
     *
     * @param filePath
     */
    public Map<String, ProtocolModel> fieldLoad(String filePath) throws FileNotFoundException {
        if (StringUtils.isEmpty(filePath)) {
            throw new FileNotFoundException("ProtocolModelLoad.fieldLoad() throw exception, filePath is empty.");
        }

        File file = new File(filePath);
        if (!file.exists()) {
            throw new FileNotFoundException("ProtocolModelLoad.fieldLoad() throw exception, file not exists");
        }

        String fileName = file.getName();
        int index = fileName.lastIndexOf(".");
        if (index == -1 || !fileName.endsWith(FILE_EXTENSION)) {
            throw new FileNotFoundException("ProtocolModelLoad.fieldLoad() throw exception, file is not model file");
        }
        Map<String, ProtocolModel> protocolModelMap = new HashMap<>(PROTOCOL_INITIAL_CAPACITY);

        ExcelReader excelReader = null;
        try {
            excelReader = ExcelUtil.getReader(FileUtil.file(file));
            Workbook workbook = excelReader.getWorkbook();
            Iterator<Sheet> sheetIterator = workbook.sheetIterator();
            while (sheetIterator.hasNext()) {
                Sheet sheet = sheetIterator.next();
                excelReader.setSheet(sheet.getSheetName());
                List<Map<String, Object>> maps = excelReader.readAll();
                ProtocolModel protocolModel = contentParse(maps, sheet.getSheetName());
                if (protocolModel != null) {
                    protocolModelMap.put(sheet.getSheetName(), protocolModel);
                }
            }
        } catch (Exception e) {
            log.error("ProtocolModelLoad.fieldLoad() handle model file throw Exception,message is:{}, cause:", e.getMessage(), e);
        } finally {
            if (excelReader != null) {
                excelReader.close();
            }
        }

        return protocolModelMap;
    }

    /**
     * 处理sheet转换成协议模型
     *
     * @return
     */
    public ProtocolModel contentParse(List<Map<String, Object>> maps, String sheetName) {
        if (maps == null || maps.isEmpty()) {
            return null;
        }

        ProtocolModel protocolModel = new ProtocolModel();
        protocolModel.setName(sheetName);
        /**
         * 设置handleType。 INDEX_HANDLE_TYPE 或 FILE_HANDLE_TYPE
         */
        if (INDEX_HANDLE_PROTOCOL[0].equals(sheetName) || INDEX_HANDLE_PROTOCOL[1].equals(sheetName) || INDEX_HANDLE_PROTOCOL[2].equals(sheetName)) {
            protocolModel.setHandleType(ProtocolHandleTypeEnum.INDEX_HANDLE_TYPE);
        } else {
            protocolModel.setHandleType(ProtocolHandleTypeEnum.FILE_HANDLE_TYPE);
        }

        /**
         * 解析模型细节
         */
        List<BaseFieldRule> baseFieldRules = maps.stream().filter(map -> {
            /**
             * 过滤掉目标字段为空的数据，防止模型备注信息被加载处理，因为目标字段是必须要存在的
             */
            String srcField = String.valueOf(map.get(DST_FIELD_NAME_KEY));
            if (StringUtils.isEmpty(srcField) || CommonContent.NULL_KEY.equals(srcField)) {
                return false;
            } else {
                return true;
            }
        }).map(map -> {
            BaseFieldRule baseFieldRule;
            /**
             * 根据handleType分别处理字段映射和索引下标两种方式的处理规则
             */
            if (protocolModel.getHandleType().equals(ProtocolHandleTypeEnum.FILE_HANDLE_TYPE)) {
                baseFieldRule = new FieldRule();
                String srcField = (String) map.get(SRC_FIELD_NAME_KEY);
                srcField = srcField.trim();
                if (!StringUtils.isEmpty(srcField)) {
                    String[] split = srcField.split(",");
                    ((FieldRule) baseFieldRule).setSrcFields(Arrays.asList(split));
                    ((FieldRule) baseFieldRule).setHandle(true);
                } else {
                    ((FieldRule) baseFieldRule).setHandle(false);
                }
            } else {
                baseFieldRule = new IndexRule();
                String srcField = map.get(SRC_NUMBER_KEY).toString();
                srcField = srcField.trim();
                if (!StringUtils.isEmpty(srcField)) {
                    String[] split = srcField.split(",");
                    ((IndexRule) baseFieldRule).setSrcIndexs(Arrays.asList(split));
                    ((IndexRule) baseFieldRule).setHandle(true);
                } else {
                    ((IndexRule) baseFieldRule).setHandle(false);
                }
            }

            /**
             * 处理模型字段信息
             */
            Field field = handleField(map);
            baseFieldRule.setField(field);

            /**
             *  字段处理规则
             */
            String rules = (String) map.get(HANDLE_RULE_KEY);
            if (!StringUtils.isEmpty(rules)) {
                String[] ruleArr = rules.split(",");
                if (ruleArr.length != 0) {
                    List<Rule> rulesInstance = Arrays.stream(ruleArr).map(RuleHandle::handle).collect(Collectors.toList());
                    if (!rulesInstance.isEmpty()) {
                        baseFieldRule.setRules(rulesInstance);
                    }
                }
            }

            return baseFieldRule;
        }).collect(Collectors.toList());

        protocolModel.setBaseFieldRules(baseFieldRules);

        return protocolModel;
    }

    /**
     * 从模型数据中初始化字段信息
     */
    private Field handleField(Map<String, Object> map) {
        Field field = new Field();
        String srcField = String.valueOf(map.get(DST_FIELD_NAME_KEY));
        if (!StringUtils.isEmpty(srcField)) {
            field.setField(srcField);
        }

        String fileTypeStr = String.valueOf(map.get(FIELD_TYPE_KEY));
        field.setFieldType(fileTypeStr);
        boolean isMust;
        try {
            isMust = (boolean) map.get(REQUIRED_FIELD_KEY);
        } catch (Exception e) {
            isMust = false;
        }
        field.setMust(isMust);

        Object defaultValue = map.get(DEFAULT_VALUE_KEY);
        field.setDefaultValue(defaultValue);
        return field;
    }
}